/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package project1;

/**
 *
 * @author rr
 */
public class TraverseThread extends Thread{
    
    private CandidateSolution sol;
    private int n = SetUp.getInstance().getLengthOfSchedule() * SetUp.getInstance().getNumberOfEmployees();
    private int level = 0;
    
    private ConstraintChecker  cc = ConstraintChecker.getInstance().getCopy();
    
    
    
    @Override
    public void run(){
        this.traverse(sol);
        ThreadedSolver.getInstance().decrementThreadCount();
    }
    
    private void traverse(CandidateSolution thisSolution) {
        this.level++;
        int n = SetUp.getInstance().getLengthOfSchedule() * SetUp.getInstance().getNumberOfEmployees();

        CandidateSolution[] solutions = new CandidateSolution[SetUp.getInstance().getNames().length];
        
        for(int i = 0; i<SetUp.getInstance().getNames().length; ++i){
            
            if(ThreadedSolver.getInstance().getSolution() != null){
                return;
            }
            
            if(thisSolution.getPossibleAssignments()[i][thisSolution.getNextVariableIndex()] == true){
                solutions[i] = thisSolution.assignNext(i);
                //System.out.println("assigned :"+solutions[i].getNumberOfAssignedValues()+" of "+n);
                //Run.printWorkSchedule(newSolution.getTempAssignments());
                
                if (solutions[i].getNumberOfAssignedValues() == n) {
                    ThreadedSolver.getInstance().setSolution(solutions[i].getTempAssignments());
                    return;
                }                  
                
            }
        }
        
        sort(solutions);
        
        for(int i = 0; i<SetUp.getInstance().getNames().length; ++i){
            if(ThreadedSolver.getInstance().getSolution() != null){
                return;
            }
            
            if(solutions[i]!=null){
                if (solutions[i].getNumberOfAssignedValues() == n) {
                     ThreadedSolver.getInstance().setSolution(solutions[i].getTempAssignments());
                    return;
                } 
                if (solutions[i].getNextVariableIndex() != -1) {
                    //Run.printWorkSchedule(solutions[i].getTempAssignments());
                    if(this.level % 30 == 0 && ThreadedSolver.getInstance().canAddThread()){
                        //start a new Thread
                        TraverseThread newThread = new TraverseThread();
                        newThread.setSol(solutions[i]);
                        ThreadedSolver.getInstance().addThread(newThread);
                    } else{
                        this.traverse(solutions[i]);
                    }
                }
            }
        }
           
      
    }
    
    
    

    private void sort(CandidateSolution[] solutions) {
        for (int i = 0; i < solutions.length; i++) {
            for (int j = i + 1; j < solutions.length; j++) {
                if (solutions[i] != null && solutions[j] != null && solutions[i].getMinimumDomainSize() < solutions[j].getMinimumDomainSize()) {
                    CandidateSolution h = solutions[i];
                    solutions[i] = solutions[j];
                    solutions[j] = h;
                }
            }
        }
    }
    
    
    
    
    

    public CandidateSolution getSol() {
        return sol;
    }

    public void setSol(CandidateSolution sol) {
        this.sol = sol;
    }
    
    
    
}
